<?php
declare (strict_types = 1);

namespace app\middleware;

use Closure;
use think\Request;
use think\Response;
use think\facade\Config;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;
use Firebase\JWT\BeforeValidException;

/**
 * JWT认证中间件
 */
class JwtMiddleware
{
    /**
     * 处理请求
     * @param Request $request 请求对象
     * @param Closure $next 闭包
     * @param array $except 排除的路由
     * @return Response
     */
    public function handle(Request $request, Closure $next, array $except = [])
    {
        // 检查当前请求是否在排除列表中
        $path = $request->pathinfo();
        if (in_array($path, $except)) {
            return $next($request);
        }
        
        // 获取token
        $token = $request->header('Authorization');
        if (empty($token)) {
            return $this->error('请先登录', [], 40101);
        }
        
        // 去除Bearer前缀
        if (strpos($token, 'Bearer ') !== false) {
            $token = str_replace('Bearer ', '', $token);
        }
        
        try {
            $jwtConfig = Config::get('jwt', []);
            $secretKey = $jwtConfig['secret_key'] ?? 'thinkphp';
            $algorithm = $jwtConfig['algorithm'] ?? 'HS256';
            
            $decoded = JWT::decode($token, new Key($secretKey, $algorithm));
            
            // 将用户信息添加到请求中
            $request->userId = $decoded->data->id;
            $request->userInfo = (array)$decoded->data;
            
            return $next($request);
        } catch (ExpiredException $e) {
            return $this->error('登录已过期，请重新登录', [], 40101);
        } catch (SignatureInvalidException $e) {
            return $this->error('无效的登录凭证', [], 40101);
        } catch (BeforeValidException $e) {
            return $this->error('登录凭证尚未生效', [], 40101);
        } catch (\Exception $e) {
            return $this->error('登录凭证验证失败', [], 40101);
        }
    }
    
    /**
     * 错误返回
     * @param string $msg 提示信息
     * @param mixed $data 返回数据
     * @param int $code 状态码
     * @return Response
     */
    protected function error(string $msg = 'error', $data = null, int $code = 40000): Response
    {
        return json([
            'code' => $code,
            'msg'  => $msg,
            'data' => $data
        ]);
    }
}